﻿using System;
using System.Collections.Generic;
using System.Text;

using MyLibrary.ThreeLayer.DataAccess.Enum;

namespace MyLibrary.ThreeLayer.DataAccess.QueryLanguage
{
    public class Condition
    {
        public readonly ConditionOperator _ConditionOperator;
        public readonly object _ConditionValue;
        public readonly string _FieldName;
        public readonly Type _TargetType;

        public Condition(ConditionOperator op)
        {
            this._TargetType = null;
            this._FieldName = String.Empty;
            this._ConditionOperator = op;
            this._ConditionValue = null;
        }

        public Condition(Type targetType, string field, ConditionOperator op, object value)
        {
            this._TargetType = targetType;
            this._FieldName = field;
            this._ConditionOperator = op;
            this._ConditionValue = value;
        }
    }

    public class ConditionExpression
    {
        private IList<Condition> _ConditionCollection = new List<Condition>();

        internal IList<Condition> ConditionCollection
        {
            get { return _ConditionCollection; }
            set { _ConditionCollection = value; }
        }

        internal ConditionExpression()
        {
        }

        private ConditionExpression And(ConditionExpression q)
        {
            this._ConditionCollection.Add(new Condition(ConditionOperator.And));
            this.CopyConditions(q);
            return this;
        }

        private ConditionExpression Or(ConditionExpression q)
        {
            this._ConditionCollection.Add(new Condition(ConditionOperator.Or));
            this.CopyConditions(q);
            return this;
        }

        internal ConditionExpression Clone()
        {
            ConditionExpression expression = new ConditionExpression();
            foreach (Condition condition in this._ConditionCollection)
                expression._ConditionCollection.Add(condition);
            return expression;
        }

        internal void CopyConditions(ConditionExpression q)
        {
            if (q._ConditionCollection.Count > 1)
            {
                this._ConditionCollection.Add(new Condition(ConditionOperator.LeftBracket));
                foreach (Condition condition in q._ConditionCollection)
                    this._ConditionCollection.Add(condition);
                this._ConditionCollection.Add(new Condition(ConditionOperator.RightBracket));
            }
            else
                foreach (Condition condition in q._ConditionCollection)
                    this._ConditionCollection.Add(condition);
        }

        public static ConditionExpression operator |(ConditionExpression q1, ConditionExpression q2)
        {
            return q1.And(q2);
        }

        public static ConditionExpression operator &(ConditionExpression q1, ConditionExpression q2)
        {
            return q1.Or(q2);
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            foreach (Condition condition in this._ConditionCollection)
            {
                if (condition._ConditionOperator == ConditionOperator.And || condition._ConditionOperator == ConditionOperator.Or)
                {
                    builder.Append(condition._ConditionOperator.ToString());
                    builder.Append(" ");
                }
                else if (condition._ConditionOperator == ConditionOperator.LeftBracket)
                    builder.Append(" (");
                else if (condition._ConditionOperator == ConditionOperator.RightBracket)
                    builder.Append(" )");
                else
                {
                    builder.Append("[")
                        .Append(condition._TargetType.Name)
                        .Append("].")
                        .Append("[")
                        .Append(condition._FieldName)
                        .Append("] ")
                        .Append(condition._ConditionOperator.ToString())
                        .Append(" ")
                        .Append(condition._ConditionValue)
                        .Append("  ");
                }
            }
            return builder.ToString();
        }
    }
}
